﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Extention.ENode.Rpc.Runtime.Communally.Entitys.Address;
using Extention.ENode.Rpc.Runtime.Communally.Serialization;
using Extention.ENode.Rpc.Runtime.Communally.Serialization.Implementation;
using Extention.ENode.Cache;
using Microsoft.Extensions.Logging;


namespace Extention.ENode.Rpc.Routing.Impl
{
    /// <summary>
    /// 路由管理，redis实现
    /// </summary>
    public class RedisServiceRouterManager : ServiceRouteManagerBase
    {

        public readonly string Key = "ESTARTCACHE:ROUTER:RPCROUTERKEY-SERVERNAME";
        public readonly string ZBalanceKey = "ESTARTCACHE:ROUTER:RPCROUTERKEY-KEY";
        private readonly ISerializer<byte[]> _byteSerializer;
        private readonly ISerializer<string> _serializer;
        private readonly IServiceRouteFactory _serviceRouteFactory;
        private readonly ILogger<RedisServiceRouterManager> _logger;
        private readonly int DB = 11;

        private readonly ICacheProvider _cacheProvider;
     

        public RedisServiceRouterManager(ISerializer<byte[]> byteSerializer, ISerializer<string> serializer,
            IServiceRouteFactory serviceRouteFactory, ILogger<RedisServiceRouterManager> logger, ICacheProvider cacheProvider) : base(serializer)
        {
            _serializer = serializer;
            _serviceRouteFactory = serviceRouteFactory;
            _logger = logger;
            _byteSerializer = byteSerializer;
            _cacheProvider = cacheProvider;
        }

        public override Task ClearAsync(IpAddressModel serverInfo)
        {
            if (_cacheProvider.KeyExists(Key + ":" + serverInfo.ServiceName, DB, false))
                _cacheProvider.KeyDelete(Key + ":" + serverInfo.ServiceName, DB, false);


            return Task.FromResult(0);
        }


        /// <summary>
        /// 获取服务
        /// </summary>
        /// <param name="serverName"></param>
        /// <returns></returns>
        public override async Task<IEnumerable<IpAddressModel>> GetBalanceAsync(string serverName)
        {
            var HasKey = await _cacheProvider.HashExistsAsync(ZBalanceKey, serverName, DB, false);
            if (HasKey)
            {
                var serverList = _cacheProvider.HashGet<List<IpAddressModel>>(ZBalanceKey, serverName, DB, false);
                if (serverList == null || serverList.Count == 0)
                {
                    if (_logger.IsEnabled(LogLevel.Error))
                    {
                        _logger.LogError($"[{serverName}]未找到有效的服务节点!");
                    }

                    //throw new Exception($"[{serverName}]未找到有效的服务节点!");
                }
                return serverList;
            }
            else
            {
                _logger.LogError($"[{serverName}]未找到有效的服务节点!");
                return new List<IpAddressModel>();
            }

        }

        /// <summary>
        /// 获取所有服务的key
        /// </summary>
        /// <returns></returns>
        public override async Task<List<string>> GetServerKey()
        {

            var serverList = await _cacheProvider.HashKeysAsync<string>(ZBalanceKey, DB, false);
            if (serverList == null || serverList.Count == 0)
            {
                if (_logger.IsEnabled(LogLevel.Error))
                {
                    _logger.LogError($"未找到有效的服务节点!");
                }
                throw new Exception($"未找到有效的服务节点!");
            }
            return serverList;


        }
        /// <summary>
        /// 获取所有路由
        /// </summary>
        /// <returns></returns>
        public override async Task<IEnumerable<ServiceRoute>> GetRoutesAsync()
        {
            ServiceRoute[] routes;
            var isHave = _cacheProvider.KeyExists(Key, DB, false);
            if (isHave)
            {
                try
                {
                    var content = _cacheProvider.HashGetAll<List<ServiceRouteDescriptor>>(Key, DB, false);
                    var result = content.SelectMany(n => n.ToList()).ToList();
                    var serializer = _serializer;
                    routes =
                        (await
                            _serviceRouteFactory.CreateServiceRoutesAsync(result)).ToArray();
                    if (_logger.IsEnabled(LogLevel.Information)) { }
                        //_logger.LogInformation(
                        //    $"成功获取到以下路由信息：{string.Join(",\n\t", routes.Select(i => i.ServiceDescriptor.Id))}");
                }
                catch (Exception exception)
                {
                    if (_logger.IsEnabled(LogLevel.Error))
                        _logger.LogError("获取路由信息时发生了错误", exception);
                    routes = new ServiceRoute[0];
                }

            }
            else
            {
                if (_logger.IsEnabled(LogLevel.Warning))
                    _logger.LogWarning($"无法获取路由信息，KEY不存在");
                routes = new ServiceRoute[0];
            }
            return routes;
        }
        /// <summary>
        /// 获取路由
        /// </summary>
        /// <returns></returns>
        public override async Task<ServiceRoute> GetRouteAsync(string serviceId)
        {
            ServiceRoute[] routes;
            var isHave = _cacheProvider.KeyExists(Key, DB, false);
            if (isHave)
            {
                try
                {
                    var allresult = _cacheProvider.HashGetAll<List<ServiceRouteDescriptor>>(Key, DB, false);
                    var result = allresult.SelectMany(n => n.ToList()).ToList();
                    var content = result.Where(n => n.ServiceDescriptor.Id == serviceId).FirstOrDefault();
                    var serializer = _serializer;
                    routes =
                        (await
                            _serviceRouteFactory.CreateServiceRoutesAsync(new List<ServiceRouteDescriptor> { content })).ToArray();
                    //if (_logger.IsEnabled(LogLevel.Information))
                    //    _logger.LogInformation(
                    //        $"成功获取到以下路由信息：{string.Join(",\n\t", routes.Select(i => i.ServiceDescriptor.Id))}");
                }
                catch (Exception exception)
                {
                    if (_logger.IsEnabled(LogLevel.Error))
                        _logger.LogError("获取路由信息时发生了错误", exception);
                    return new ServiceRoute();
                }

            }
            else
            {
                if (_logger.IsEnabled(LogLevel.Warning))
                    _logger.LogWarning($"无法获取路由信息，KEY不存在");
                return new ServiceRoute();
            }
            if (routes.Count() > 0)
            {
                return routes[0];
            }
            else
            {
                return new ServiceRoute();
            }

        }

        /// <summary>
        /// 设置路由
        /// </summary>
        /// <param name="routes"></param>
        /// <param name="serverInfo"></param>
        /// <returns></returns>
        protected override async Task SetRoutesAsync(IEnumerable<ServiceRouteDescriptor> routes, IpAddressModel serverInfo)
        {
            try
            {
                await _cacheProvider.HashSetAsync(Key, serverInfo.ServiceName, _serializer.Serialize(routes), DB, false);
            }
            catch (Exception ex)
            {
                if (_logger.IsEnabled(LogLevel.Error))
                    _logger.LogError("设置路由信息时发生了错误", ex);
            }

        }


        public override async Task SetBalanceAsync(IpAddressModel serverInfo)
        {

            await ClearAsync(serverInfo);
            var HasKey = await _cacheProvider.HashExistsAsync(ZBalanceKey, serverInfo.ServiceName, DB, false);
            if (HasKey)
            {
                var serverList = _cacheProvider.HashGet<List<IpAddressModel>>(ZBalanceKey, serverInfo.ServiceName, DB, false);
                if (serverList == null)
                {
                    serverList = new List<IpAddressModel>();
                }
                var server = serverList.Where(n => n.Ip == serverInfo.Ip).Where(n => n.Port == serverInfo.Port).FirstOrDefault();

                if (server == null)
                {
                    serverList.Add(serverInfo);
                    await _cacheProvider.HashSetAsync(ZBalanceKey, serverInfo.ServiceName, serverList, DB, false);
                }
                else
                {
                    server.HealthyCheckUrl = serverInfo.HealthyCheckUrl;
                    server.ServiceName = serverInfo.ServiceName;
                    server.HealthyCheckPort = serverInfo.HealthyCheckPort;
                    await _cacheProvider.HashSetAsync(ZBalanceKey, serverInfo.ServiceName, serverList, DB, false);
                }
            }
            else
            {
                var serverList = new List<IpAddressModel>
                    {
                        serverInfo
                    };
                await _cacheProvider.HashSetAsync(ZBalanceKey, serverInfo.ServiceName, serverList, DB, false);
            }
        }
    }
}
